package com.seven.first.ms.base;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.seven.first.dao.base.SevenBaseMapper;
import com.seven.first.suite.annotation.handler.DeleteField;
import com.seven.first.suite.annotation.handler.TableAnnotationHandler;
import com.seven.first.suite.base.BaseDTO;
import com.seven.first.suite.base.BasePO;
import com.seven.first.suite.base.QueryDTO;
import com.seven.first.suite.result.ApiResult;
import ma.glasnost.orika.MapperFacade;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;

import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Optional;


/**
 * @author seven
 */
public abstract class AbstractBaseServiceImpl<PO extends BasePO, DTO extends BaseDTO, QUERY extends QueryDTO> implements BaseService<PO, DTO, QUERY> {

    private static final Logger log = LoggerFactory.getLogger(AbstractBaseServiceImpl.class);

    protected static final Long ROOT_ID = 0L;

    @Autowired
    protected MapperFacade mapperFacade;

    @Autowired
    protected SevenBaseMapper<PO, QUERY> sevenBaseMapper;

    @Autowired
    protected JdbcTemplate jdbcTemplate;

    /**
     * todo  ID 生成方法
     */
//    @Autowired
//    protected IdService idService;

    private Class<PO> poClass;

    private Class<DTO> dtoClass;

    protected List<DTO> mapAsList(List<PO> pos) {
        return this.mapperFacade.mapAsList(pos, this.getDTOClass());
    }

    protected DTO mapAsDTO(PO po) {
        return this.mapperFacade.map(po, this.getDTOClass());
    }

    protected PO mapAsPO(DTO dto) {
        return this.mapperFacade.map(dto, this.getPOClass());
    }

    protected Class<PO> getPOClass() {
        if (this.poClass == null) {
            this.poClass = (Class<PO>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        }
        return this.poClass;
    }

    protected Class<DTO> getDTOClass() {
        if (this.dtoClass == null) {
            this.dtoClass = (Class<DTO>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        }
        return this.dtoClass;
    }

    /**
     * 分页查询
     * todo  设置ID
     *
     * @param po
     * @return
     */
    @Override
    public ApiResult<PO> insert(PO po) {
        if (po.getId() == null) {
            po.setId(5L);
        }
        this.sevenBaseMapper.insert(po);
        return ApiResult.ok(po);
    }

    /**
     * 分页查询
     * todo  设置ID
     *
     * @param dto
     * @return
     */
    @Override
    public ApiResult<DTO> insertDTO(DTO dto) {
        PO po = this.mapAsPO(dto);
        po.setId(5L);
        ApiResult<PO> poResult = this.insert(po);
        if (poResult.isPresent()) {
            return ApiResult.ok(mapAsDTO(poResult.getData()));
        }
        return ApiResult.error(poResult.getStatus(), poResult.getErrorMsg());
    }

    @Override
    public ApiResult<PO> update(PO po) {
        if (po.getId() == null) {
            return ApiResult.error(500, "PO's id can't blank !");
        }
        this.sevenBaseMapper.updateByPrimaryKey(po);
        return ApiResult.ok(po);
    }

    @Override
    public ApiResult<DTO> updateDTO(DTO dto) {
        PO po = this.mapAsPO(dto);
        ApiResult<PO> poResult = this.update(po);
        if (poResult.isPresent()) {
            return ApiResult.ok(mapAsDTO(poResult.getData()));
        }
        return ApiResult.error(poResult.getStatus(), poResult.getErrorMsg());
    }

    @Override
    public ApiResult<PO> updateByPrimaryKeySelective(PO po) {
        if (po.getId() == null) {
            return ApiResult.error(500, "PO's id can't blank !");
        }
        this.sevenBaseMapper.updateByPrimaryKeySelective(po);
        return ApiResult.ok(po);
    }

    @Override
    public ApiResult<DTO> updateByPrimaryKeySelective(DTO dto) {
        PO po = this.mapAsPO(dto);
        ApiResult<PO> poResult = this.updateByPrimaryKeySelective(po);
        if (poResult.isPresent()) {
            return ApiResult.ok(mapAsDTO(poResult.getData()));
        }
        return ApiResult.error(poResult.getStatus(), poResult.getErrorMsg());
    }


    @Override
    public Optional<PO> findById(Long id) {
        PO po = this.sevenBaseMapper.selectByPrimaryKey(id);
        if (po == null) {
            return Optional.empty();
        }
        return Optional.of(po);
    }

    @Override
    public ApiResult<DTO> findDTOById(Long id) {
        Optional<PO> po = findById(id);
        if (!po.isPresent()) {
            return ApiResult.error(400, "通过ID未查询到PO");
        }
        return po.map(po1 -> ApiResult.ok(this.mapAsDTO(po1)))
                .orElseGet(ApiResult::ok);
    }

    @Override
    public List<DTO> list(QUERY query) {
        listPO(query);
        return this.mapAsList(listPO(query));
    }

    @Override
    public List<PO> listPO(QUERY query) {
        return this.sevenBaseMapper.listByQuery(query);
    }

    public PageInfo<PO> selectPage(QUERY query) {
        Page<PO> page = PageHelper.startPage(query.getPageNum(), query.getPageSize());
        return page.doSelectPageInfo(() -> this.sevenBaseMapper.listByQuery(query));
    }


    @Override
    public ApiResult<PageInfo<DTO>> selectDTOPage(QUERY query) {
        PageInfo<PO> page = selectPage(query);
        PageInfo<DTO> pageResult = new PageInfo<>();
        pageResult.setPageNum(page.getPageNum());
        pageResult.setPageSize(page.getPageSize());
        pageResult.setTotal(page.getTotal());
        pageResult.setHasNextPage(page.isHasNextPage());
        pageResult.setEndRow(page.getEndRow());
        pageResult.setHasPreviousPage(page.isHasPreviousPage());
        pageResult.setIsFirstPage(page.isIsFirstPage());
        pageResult.setIsLastPage(page.isIsLastPage());
        if (page.getList() != null) {
            pageResult.setList(this.mapAsList(page.getList()));
        }
        return ApiResult.ok(pageResult);
    }


    @Override
    public ApiResult<Integer> deleteLogicallyByIds(List<Long> ids) {
        //获取删除注解的字段名
        DeleteField deleteFieldValue = TableAnnotationHandler.getDeleteFieldValue(poClass);
        //获取表名
        String tableNameValue = TableAnnotationHandler.getTableNameValue(poClass);
        //拼装sql
        String sql = "UPDATE " + tableNameValue + " SET " + deleteFieldValue.getField() + " = " + deleteFieldValue.getDeleteValue() + ";";
        log.info("执行的SQL为：{}", sql);
        //执行SQL
        return ApiResult.ok(jdbcTemplate.update(sql));
    }

    @Override
    public ApiResult<Integer> recoveryLogicallyByIds(List<Long> ids) {
        //获取删除注解的字段名
        DeleteField deleteFieldValue = TableAnnotationHandler.getDeleteFieldValue(poClass);
        //获取表名
        String tableNameValue = TableAnnotationHandler.getTableNameValue(poClass);
        //拼装sql
        String sql = "UPDATE " + tableNameValue + " SET " + deleteFieldValue.getField() + " = " + deleteFieldValue.getExistValue() + ";";
        log.info("执行的SQL为：{}", sql);
        //执行SQL
        return ApiResult.ok(jdbcTemplate.update(sql));
    }
}
